<?php
final class hash {
	
	static private $SysKey;
	
	static public function SetKey(&$key)
	{
		self::$SysKey = $key;
		$key = null;
	}
	
	private $key;
	
	public function __construct($key = null)
	{
		$this->key = $key == null ? self::$SysKey : $key;
	}

	public function hash($pass, $decal = null){
		$builder = '';
		$decal = $decal === null ? rand(0, 15) : $decal;
		$pass = sha1($pass);
		for ($i = 0; $i < strlen($pass) * 2; $i++)
		{
			if ($i % 2 == 0) {
				$builder .= $pass[$i / 2];
			}
			else
			{
				$builder .= substr($this->key, ($i / 2 + $decal) % 20, 1);
			}
		}
		return $this->AddDecal('#'.md5($builder), $decal);
	}
	
	/**
	 * Check if a pass is agree with a hash
	 * @param string pass
	 * @param string NK_Hash
	 **/
	public function Check_Hash($pass, $hash){
		if (substr($hash, 0, 1) == '%')
			$pass = md5($pass);
	
		if (substr($hash, 0, 1) == '%' || substr($hash, 0, 1) == '#') {
			$decal = hexdec($this->GetDecal($hash));
			return substr($hash, 1) == substr($this->hash($pass, $decal), 1);
		}
		else
			die('Have you run update.php ? Old password was dissallowed !');
	}
	
	private function DecalPos()
	{
		$pos = 0;
		for ($i = 0; $i < strlen($this->key); $i++)
		{
			$char = ord($this->key[$i]);

			if ($char & 0x01000000)
				$char *= $char & 0x00001111;

			if ($char & 0x00100000)
				$char += $char & 0x00001111;
			
			if ($char & 0x00010000)
				$char -= $char & 0x11100000 / 0x00011111;
			
			$pos = $pos + $char % 32;
		}
		return $pos;
	}
	
	private function GetDecal($hash)
	{
		$pos = $this->DecalPos();
		return substr($hash, $pos + 1, 1);
	}
	
	private function AddDecal($hash, $decal)
	{
		$pos = $this->DecalPos();
		return substr($hash, 0, $pos + 1)
			. dechex($decal)
			. substr($hash, $pos + 1);
	}
}